﻿using System;
using System.Collections.Generic;

namespace Grinder.Settings
{
    public abstract class SettingsBase : IDisposable
    {
        private readonly IDictionary<string, Section> _sections = new Dictionary<string, Section>();

        protected string File { get; set; }
        protected internal IDictionary<string, Section> Sections { get { return _sections; } }

        public abstract void Save();
        public abstract void Load();

        protected SettingsBase(string file)
        {
            File = file;
        }
        
        public virtual Section AddSection(string name)
        {
            if (name == null) throw new ArgumentNullException("name");
            var section = new Section(name);

            _sections.Add(name, section);

            return section;
        }

        public void Dispose()
        {
            Save();
        }

        public void SetValue(string section, string key, object value)
        {
            if (section == null) throw new ArgumentNullException("section");
            if (key == null) throw new ArgumentNullException("key");
            if (value == null) throw new ArgumentNullException("value");

            Section sec;

            try
            {
                sec = _sections[section];
            }
            catch (KeyNotFoundException)
            {
                sec = new Section(section);
                _sections.Add(sec.Name, sec);
            }

            sec.AddValue(key, value.ToString());
        }

        public string GetValue(string section, string key)
        {
            if (section == null) throw new ArgumentNullException("section");
            if (key == null) throw new ArgumentNullException("key");

            Section sec;

            try
            {
                sec = _sections[section];
            }
            catch (KeyNotFoundException)
            {
                throw new SectionNotFoundException("Section not found: ", section);
            }

            return sec.GetValue(key);
        }

        public int GetIntValue(string section, string key)
        {
            return Int32.Parse(GetValue(section, key));
        }

        public bool GetBooleanValue(string section, string key)
        {
            return Boolean.Parse(GetValue(section, key));
        }

        public T GetEnumValue<T>(string section, string key)
        {
            string value = GetValue(section, key);
            return (T)Enum.Parse(typeof(T), value);
        }

        public void RemoveSection(string section)
        {
            if (section == null) throw new ArgumentNullException("section");

            _sections.Remove(section);
        }

        public void RemoveValue(string section, string key)
        {
            if (section == null) throw new ArgumentNullException("section");
            if (key == null) throw new ArgumentNullException("key");

            if (!_sections.ContainsKey(section)) return;

            Section sec = _sections[section];

            sec.RemoveValue(key);
        }
    }
}
